/* Copyright (c) 2022 渝州大数据实验室
 *
 * Lanius is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.yzbdl.lanius.orchestrate.serv.quartz.resource;

import cn.hutool.core.lang.TypeReference;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.yzbdl.lanius.orchestrate.serv.constant.TaskResourceConstant;
import org.yzbdl.lanius.orchestrate.serv.dataBase.DynamicDataBase;
import org.yzbdl.lanius.orchestrate.serv.dto.resource.ServerProgramAndServerDto;
import org.yzbdl.lanius.orchestrate.serv.entity.resource.ServerEntity;
import org.yzbdl.lanius.orchestrate.serv.entity.resource.ServerProgramEntity;
import org.yzbdl.lanius.orchestrate.serv.entity.resource.TaskResourceConfigEntity;
import org.yzbdl.lanius.orchestrate.serv.enums.ResourceDataStatusEnum;
import org.yzbdl.lanius.orchestrate.serv.enums.ServerProgramStatusEnum;
import org.yzbdl.lanius.orchestrate.serv.mapper.resource.ServerMapper;
import org.yzbdl.lanius.orchestrate.serv.mapper.resource.ServerProgramMapper;
import org.yzbdl.lanius.orchestrate.serv.mapper.resource.TaskResourceConfigMapper;
import org.yzbdl.lanius.orchestrate.serv.service.resource.ServerProgramService;
import org.yzbdl.lanius.orchestrate.serv.utils.SshUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 资源定时任务
 *
 * @author zhuhongji@yzbdl.ac.cn
 * @date 2022-04-20 15:05
 */
@Component
@AllArgsConstructor
public class ResourceScheduledTask {

    private static final Logger logger = LoggerFactory.getLogger(ResourceScheduledTask.class);

    private final ServerMapper serverMapper;

    private final TaskResourceConfigMapper taskResourceConfigMapper;

    private final ServerProgramService serverProgramService;

    private final ServerProgramMapper serverProgramMapper;

    /**
     * 服务器状态检测定时任务
     */
    @Scheduled(cron = "${cron.resource.server}")
    public void serverScheduledTask() {
        logger.info("定时任务检测主机配置状态！");
        List<ServerEntity> all = serverMapper.getAllServer();
        List<ServerEntity> checkedList = new ArrayList<>();
        all.forEach(server -> {
            boolean isConnected = SshUtils.serverTestConnection(server.getServerIp(), server.getServerPort(),
                    server.getAccountName(), server.getPassword());
            Integer status = isConnected ? ResourceDataStatusEnum.NORMAL.getCode() : ResourceDataStatusEnum.ABNORMAL.getCode();
            if (!status.equals(server.getStatus())) {
                checkedList.add(ServerEntity.builder().id(server.getId()).status(status).build());
            }
        });
        if (!CollectionUtils.isEmpty(checkedList)) {
            serverMapper.batchUpdate(checkedList);
        }
    }

    /**
     * 资源配置(数据库)定时任务
     */
    @Scheduled(cron = "${cron.resource.taskResourceConfig}")
    public void taskResourceConfigScheduledTask() {
        logger.info("定时任务检测资源配置状态！");
        List<TaskResourceConfigEntity> all = taskResourceConfigMapper.getAllTaskResource();
        List<TaskResourceConfigEntity> checkedList = new ArrayList<>();
        all.forEach(config -> {
            Boolean isConnected = DynamicDataBase.testConnection(config.getConnectUrl(), config.getConnectAccount(),
                    config.getConnectPassword());
            Integer status =
                    isConnected ? ResourceDataStatusEnum.NORMAL.getCode() : ResourceDataStatusEnum.ABNORMAL.getCode();
            // 仅状态更新时需要更新
            if (!config.getStatus().equals(status)) {
                checkedList.add(TaskResourceConfigEntity.builder().id(config.getId()).status(status).build());
            }
        });
        if (!CollectionUtils.isEmpty(checkedList)) {
            taskResourceConfigMapper.batchUpdate(checkedList);
        }
    }

    /**
     * 服务节点定时任务
     */
    @Scheduled(cron = "${cron.resource.serverProgram}")
    public void serverProgramScheduledTask() {
        logger.info("定时任务检测服务节点状态！");
        List<ServerProgramAndServerDto> all = serverProgramMapper.getAllServerProgramAndServerInfo();
        List<ServerProgramEntity> checkedServerProgramList = new ArrayList<>();
        List<ServerEntity> checkedServerList = new ArrayList<>();
        all.forEach(serverProgram -> {
            // 解析json配置数据
            Map<String, String> hashMap =
                    JSONUtil.toBean(JSONUtil.parse(serverProgram.getAuthConfig()), new TypeReference<>() {
                    }, true);
            Integer status = serverProgramService.testConnectionExecuteByScheduled(serverProgram.getServerId(),
                    serverProgram.getServerIp(), serverProgram.getProgramPort(),
                    hashMap.get(TaskResourceConstant.SERVER_PROGRAM_USERNAME),
                    hashMap.get(TaskResourceConstant.SERVER_PROGRAM_PASSWORD));
            // 当与原始状态不同时变更数据
            if (!serverProgram.getStatus().equals(status)) {
                checkedServerProgramList.add(ServerProgramEntity.builder()
                        .id(serverProgram.getId()).status(status).build());
                // 如果服务节点异常，或停止；然后检查服务器状态
                if (ServerProgramStatusEnum.ABNORMAL.getCode().equals(status) ||
                        ServerProgramStatusEnum.STOPPED.getCode().equals(status)) {
                    boolean isServerConnected = SshUtils.serverTestConnection(serverProgram.getServerIp(),
                            serverProgram.getServerPort(),
                            serverProgram.getServerAccountName(),
                            serverProgram.getServerPassword());
                    Integer serverStatus = isServerConnected ? ServerProgramStatusEnum.RUNNING.getCode()
                            : ServerProgramStatusEnum.STOPPED.getCode();
                    if (!serverProgram.getServerStatus().equals(serverStatus)) {
                        checkedServerList
                                .add(ServerEntity.builder().id(serverProgram.getServerId()).status(serverStatus).build());
                    }
                }
            }
        });
        // 更新服务节点数据
        if (!CollectionUtils.isEmpty(checkedServerProgramList)) {
            serverProgramMapper.batchUpdate(checkedServerProgramList);
        }
        // 更新服务器器状态
        if (!CollectionUtils.isEmpty(checkedServerList)) {
            serverMapper.batchUpdate(checkedServerList);
        }
    }

}
